package hikari.gui.guicomponents;

import com.gooddies.wiring.Wiring;
import com.gooddies.wiring.annotations.PostWiring;
import com.gooddies.wiring.annotations.Wire;
import com.gooddies.wiring.annotations.WiringComponent;
import hikari.gui.MainWindow;
import hikari.managers.ActionManager;
import hikari.managers.AssetsManager;
import hikari.managers.Manager3D;
import hikari.managers.NavmeshManager;
import hikari.managers.PhysicManager;
import hikari.managers.RunManager;
import hikari.managers.ScriptManager;
import hikari.managers.TemplateManager;
import hikari.objects3d.BillBoard3dObject;
import hikari.objects3d.Camera3dObject;
import hikari.objects3d.Cube3dObject;
import hikari.objects3d.Particle3dObject;
import hikari.objects3d.Sphere3dObject;
import hikari.objects3d.light.ConeLight3dObject;
import hikari.objects3d.light.DirectionalLight3dObject;
import hikari.objects3d.light.Light3dObject;
import hikari.objects3d.light.OmniLight3dObject;
import hikari.preferences.GameProperties;
import hikari.preferences.SceneProperties;
import hikari.preferences.device_parameters.DeviceConfigurationDialog;
import hikari.preferences.device_parameters.DeviceParameters;
import hikari.preferences.scene_parameters.SceneConfigurationDialog;
import hikari.script.ScriptRegisterProcessor;
import hikari.utils.Utils;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

/**
 * @author sad
 */
@WiringComponent(singleton = true, lazy = true)
public class MainMenuBar extends JMenuBar {

    @Wire
    private Manager3D manager3D;
    @Wire
    private GameProperties gameProperties;
    @Wire
    private RunManager runManager;
    @Wire
    private ScriptManager scriptManager;
    @Wire
    private ActionManager actionManager;
    @Wire
    private AssetsManager assetsManager;
    @Wire
    private NavmeshManager navmeshManager;
    @Wire
    private PhysicManager physicManager;
    @Wire
    private MainWindow mainWindow;
    @Wire
    private Utils utils;

    private MainMenuBar() {
    }

    @PostWiring
    private void init() {
        addTopMenu("File", "file_menu");
        addTopMenu("Edit", "edit_menu");
        addTopMenu("Run", "run_menu");
        addTopMenu("Object", "create_object_menu");
        addTopMenu("Component", "component_menu");
        addTopMenu("Assets", "asset_menu");
        addTopMenu("Template", "template_menu");
        addTopMenu("Settings", "settings_menu");
        addTopMenu("Help", "help_menu");
        fillRunMenuBar();
        fillObjectMenuBar();
        fillFileMenuBar();
        fillComponentMenuBar();
        fillSettingsMenuBar();
        fillTemplateMenuBar();
        fillAssetMenuBar();
    }

    private JMenu addTopMenu(String caption, String id) {
        JMenu item = new JMenu(caption);
        item.setName(id);
        add(item);
        return item;
    }

    public JMenu getTopMenuItem(String id) {
        for (int i = 0; i < getMenuCount(); i++) {
            JMenu menu = getMenu(i);
            if (menu.getName() != null && menu.getName().equals(id)) {
                return menu;
            }
        }
        return null;
    }

    public JMenu addSubMenu(JMenu topMenu, String caption, final String action) {
        JMenu menu = new JMenu(caption);
        menu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionManager.invokeAction(action);
            }
        });
        topMenu.add(menu);
        return menu;
    }

    public JMenuItem addSubMenuItem(JMenu topMenu, String caption, final String action) {
        JMenuItem menu = new JMenuItem(caption);
        menu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionManager.invokeAction(action);
            }
        });
        topMenu.add(menu);
        return menu;
    }

    protected void fillFileMenuBar() {
        JMenu menu = getTopMenuItem("file_menu");
        addSubMenuItem(menu, "New Project", "create_new_project");
        addSubMenuItem(menu, "Open Project", "open_project");
        addSubMenuItem(menu, "New Scene", "create_new_scene");
        addSubMenuItem(menu, "Open Scene", "open_scene");
        addSubMenuItem(menu, "Save Scene", "save_scene");
        addSubMenuItem(menu, "Save Scene as...", "save_scene_as");
        addSubMenuItem(menu, "Exit", "exit");

        actionManager.addAction("create_new_project", new Runnable() {
            @Override
            public void run() {
                mainWindow.newProject();
            }
        });

        actionManager.addAction("open_project", new Runnable() {
            @Override
            public void run() {
                mainWindow.openProject();
            }
        });

        actionManager.addAction("create_new_scene", new Runnable() {
            @Override
            public void run() {
                mainWindow.newScene();
            }
        });
        actionManager.addAction("open_scene", new Runnable() {
            @Override
            public void run() {
                mainWindow.open();
            }
        });
        actionManager.addAction("save_scene", new Runnable() {
            @Override
            public void run() {
                mainWindow.save();
            }
        });
        actionManager.addAction("save_scene_as", new Runnable() {
            @Override
            public void run() {
                mainWindow.saveAs();
            }
        });
        actionManager.addAction("exit", new Runnable() {
            @Override
            public void run() {
                mainWindow.exit();
            }
        });
    }

    protected void fillRunMenuBar() {
        JMenu menu = getTopMenuItem("run_menu");
        addSubMenuItem(menu, "Run game", "run_game");
        addSubMenuItem(menu, "Run scene", "run_scene");
        addSubMenuItem(menu, "Reload scripts", "reload_scripts");

        actionManager.addAction("run_game", new Runnable() {
            @Override
            public void run() {
                runManager.runGame();
            }
        });
        actionManager.addAction("run_scene", new Runnable() {
            @Override
            public void run() {
                runManager.runScene();
            }
        });
        actionManager.addAction("reload_scripts", new Runnable() {
            @Override
            public void run() {
                ScriptRegisterProcessor processor = (ScriptRegisterProcessor) Wiring.getComponent(ScriptRegisterProcessor.class);
                processor.process();
            }
        });
    }

    protected void fillObjectMenuBar() {
        JMenu menu = getTopMenuItem("create_object_menu");
        addSubMenuItem(menu, "Cube", "create_cube_object");
        addSubMenuItem(menu, "Sphere", "create_sphere_object");
        //addSubMenuItem(menu, "Terrain", "create_terrain_object");
        addSubMenuItem(menu, "Omni Light", "create_omni_light_object");
        addSubMenuItem(menu, "Cone Light", "create_cone_light_object");
        addSubMenuItem(menu, "Directional Light", "create_directional_light_object");
        addSubMenuItem(menu, "Camera", "create_camera_object");
        addSubMenuItem(menu, "BillBoard", "create_billboard_object");
        addSubMenuItem(menu, "Particle System", "create_particle_object");
        addSubMenuItem(menu, "Navmesh", "create_navmesh_object");

        actionManager.addAction("create_cube_object", new Runnable() {
            @Override
            public void run() {
                Cube3dObject cube = new Cube3dObject(manager3D.getSceneManager());
                manager3D.AddObject(cube);
                utils.setModified();
            }
        });
        actionManager.addAction("create_omni_light_object", new Runnable() {
            @Override
            public void run() {
                Light3dObject light = new OmniLight3dObject(manager3D.getSceneManager());
                manager3D.AddObject(light);
                utils.setModified();
            }
        });
        actionManager.addAction("create_cone_light_object", new Runnable() {
            @Override
            public void run() {
                Light3dObject light = new ConeLight3dObject(manager3D.getSceneManager());
                manager3D.AddObject(light);
                utils.setModified();
            }
        });
        actionManager.addAction("create_directional_light_object", new Runnable() {
            @Override
            public void run() {
                Light3dObject light = new DirectionalLight3dObject(manager3D.getSceneManager());
                manager3D.AddObject(light);
                utils.setModified();
            }
        });
        actionManager.addAction("create_camera_object", new Runnable() {
            @Override
            public void run() {
                Camera3dObject camera = new Camera3dObject(manager3D.getSceneManager());
                manager3D.AddObject(camera);
                utils.setModified();
            }
        });
        actionManager.addAction("create_sphere_object", new Runnable() {
            @Override
            public void run() {
                Sphere3dObject cube = new Sphere3dObject(manager3D.getSceneManager());
                manager3D.AddObject(cube);
                utils.setModified();
            }
        });
        actionManager.addAction("create_billboard_object", new Runnable() {
            @Override
            public void run() {
                BillBoard3dObject billboard = new BillBoard3dObject(manager3D.getSceneManager());
                manager3D.AddObject(billboard);
                utils.setModified();
            }
        });
        actionManager.addAction("create_particle_object", new Runnable() {
            @Override
            public void run() {
                Particle3dObject particleObject = new Particle3dObject(manager3D.getSceneManager());
                manager3D.AddObject(particleObject);
                utils.setModified();
            }
        });
        actionManager.addAction("create_navmesh_object", new Runnable() {
            @Override
            public void run() {
                navmeshManager.addNavmesh();
            }
        });
        /* ActionManager.getInstance().addAction("create_terrain_object", new Runnable() {
         @Override
         public void run() {
         Terrain3dObject terrain = new Terrain3dObject(Manager3D.getInstance().getSceneManager());
         Manager3D.getInstance().AddObject(terrain);
         }
         });*/
    }

    protected void fillComponentMenuBar() {
        JMenu componentMenuItem = getTopMenuItem("component_menu");
        addSubMenuItem(componentMenuItem, "Script", "script_action");
        actionManager.addAction("script_action", new Runnable() {
            @Override
            public void run() {
                scriptManager.addScriptToSelectedObject();
                utils.setModified();
            }
        });

        addSubMenuItem(componentMenuItem, "Physics", "physics_action");
        actionManager.addAction("physics_action", new Runnable() {
            @Override
            public void run() {
                physicManager.addPhysicToSelectedObject();
                utils.setModified();
            }
        });
        addSubMenuItem(componentMenuItem, "Navmesh Agent", "navmesh_agent_action");
        actionManager.addAction("navmesh_agent_action", new Runnable() {
            @Override
            public void run() {
                navmeshManager.addNavmeshAgentComponentToSelectedObject();
                utils.setModified();
            }
        });
    }

    protected void fillTemplateMenuBar() {
        JMenu templateMenuItem = getTopMenuItem("template_menu");
        addSubMenuItem(templateMenuItem, "New Template", "template_action");
        actionManager.addAction("template_action", new Runnable() {
            @Override
            public void run() {
                TemplateManager.getInstance().createTemplate();
                utils.setModified();
            }
        });
    }

    private void fillSettingsMenuBar() {
        JMenu settingsMenuItem = getTopMenuItem("settings_menu");
        addSubMenuItem(settingsMenuItem, "Device Settings...", "device_settings_action");
        actionManager.addAction("device_settings_action", new Runnable() {
            @Override
            public void run() {
                DeviceParameters params = gameProperties.getDeviceParameters();
                DeviceConfigurationDialog dialog = new DeviceConfigurationDialog(mainWindow, params);
                if (dialog.showDialog()) {
                    try {
                        manager3D.saveProjectFile();
                    } catch (IOException ex) {
                        utils.logError(ex);
                        utils.errorMessage(mainWindow, "Cannot save device properties");
                    }
                }
            }
        });

        addSubMenuItem(settingsMenuItem, "Scene Settings...", "scene_settings_action");
        actionManager.addAction("scene_settings_action", new Runnable() {
            @Override
            public void run() {
                SceneProperties params = (SceneProperties) Wiring.getComponent(SceneProperties.class);
                SceneConfigurationDialog dialog = new SceneConfigurationDialog(mainWindow, params);
                if (dialog.showDialog()) {
                    params.updateScene();
                }
                //DeviceConfigurationDialog dialog=new DeviceConfigurationDialog(MainWindow.getInstance(), params);
                //dialog.showDialog();
                utils.setModified();
            }
        });
    }

    protected void fillAssetMenuBar() {
        JMenu componentMenuItem = getTopMenuItem("asset_menu");
        addSubMenuItem(componentMenuItem, "Create Asset", "create_asset_action");
        actionManager.addAction("create_asset_action", new Runnable() {
            @Override
            public void run() {
                assetsManager.saveAssetToArchive();
            }
        });
        addSubMenuItem(componentMenuItem, "Import Asset", "import_asset_action");
        actionManager.addAction("import_asset_action", new Runnable() {
            @Override
            public void run() {
                assetsManager.importAssetToArchive();
            }
        });
    }
}
